#ifndef __MSGHANDLE_CPP__
#define __MSGHANDLE_CPP__

#include "env.h"
#include "bytearrays.h"
#include "section.h"
#include "output.h"
#include "msghandle.h"
#include "msgqueue.h"
#include "bytearrays.h"
#include "timecallback.h"

using namespace WServer::Section;
using namespace WServer::MsgQueue;
using namespace WServer::GData;

void* MsgHandleCb(void* arg)
{
	wserPrintMsg("MsgHandleCb. pid:%d\n", syscall(SYS_gettid));
	pthread_detach(pthread_self());
	struct WServer::MsgHandle::wmsgdata* msg;
	int ret;
	char cdata[MEMORYPOOLSIZE];
	while (1) {
		memset(cdata, 0, MEMORYPOOLSIZE);
		if (pthread_mutex_lock(&WServer::MsgHandle::m_msgrcvMutex) == 0) {
			ret = msgrcv(modulelist[WServer::GData::moduleindex].msgid, cdata, MEMORYPOOLSIZE, 0, 0);
			if (ret >= 0) {
				msg = new struct WServer::MsgHandle::wmsgdata();
				if (msg->msgstream(cdata)) {
					HandleMessage(msg);
				}
				else {
					delete msg;msg = NULL;
				}
			}
			pthread_mutex_unlock(&WServer::MsgHandle::m_msgrcvMutex);
		}
		usleep(10);
	}
	return NULL;
}

void SendMessage(int from, int to, long type, int clientindex, int datasize, void* param)
{
	int i;
	i = msgsnd(WServer::GData::modulelist[to].msgid, param, datasize+12-sizeof(long), 0);
	if (i == -1) {
		wserPrintErr("SendMessage error. type:%d to:%d size:%d clientindex:%d. %s\n", type, to, datasize, clientindex, strerror(errno));
	}
	else {
	}
}

void CreateMessage(int from, int to, long type, int clientindex, int datasize, void* param)
{
	struct WServer::MsgHandle::wmsgdata* pmsg = new struct WServer::MsgHandle::wmsgdata();
	pmsg->makestream(from, to, type, clientindex, datasize, param);
	SendMessage(pmsg->from, pmsg->to, pmsg->type, pmsg->clientindex, pmsg->len, pmsg->param);
	delete pmsg;
}

namespace WServer {

namespace MsgHandle {
pthread_mutex_t m_msgrcvMutex;
std::map<int, msginfo> msglist;

void SendMessage2WMain(long type, int clientindex, int len, void* param)
{
	if (clientindex <= 0) return;
	if (msglist.find(type) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, type);return;}
	if (msglist[type].msgto & wmainmsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, type, msglist[type].msgto);return;}
	SendMessage(GData::moduleindex, wmainindex, type, clientindex, len, param);
}

void CreateMessage2WMain(int clientindex, MsgBaseClass& msgclass)
{
	if (clientindex <= 0) return;
	if (msglist.find(msgclass.msgtype) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, msgclass.msgtype);return;}
	if (msglist[msgclass.msgtype].msgto & wmainmsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, msgclass.msgtype, msglist[msgclass.msgtype].msgto);return;}
	byteArrays ba = msgclass.encodeMsgClass();
	CreateMessage(GData::moduleindex, wmainindex, msgclass.msgtype, clientindex, ba.getlength(), ba.toVoid());
}

void CreateMessage2WMysql(int clientindex, MsgBaseClass& msgclass)
{
	if (clientindex <= 0) return;
	if (msglist.find(msgclass.msgtype) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, msgclass.msgtype);return;}
	if (msglist[msgclass.msgtype].msgto & wmysqlmsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, msgclass.msgtype, msglist[msgclass.msgtype].msgto);return;}
	byteArrays ba = msgclass.encodeMsgClass();
	CreateMessage(GData::moduleindex, wmysqlindex, msgclass.msgtype, clientindex, ba.getlength(), ba.toVoid());
}

void CreateMessage2WSocket(int clientindex, MsgBaseClass& msgclass)
{
	if (clientindex <= 0) return;
	if (msglist.find(msgclass.msgtype) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, msgclass.msgtype);return;}
	if (msglist[msgclass.msgtype].msgto & wsocketmsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, msgclass.msgtype, msglist[msgclass.msgtype].msgto);return;}
	byteArrays ba = msgclass.encodeMsgClass();
	CreateMessage(GData::moduleindex, wsocketindex, msgclass.msgtype, clientindex, ba.getlength(), ba.toVoid());
}

void CreateMessage2WPhp(int clientindex, MsgBaseClass& msgclass)
{
	if (clientindex <= 0) return;
	if (msglist.find(msgclass.msgtype) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, msgclass.msgtype);return;}
	if (msglist[msgclass.msgtype].msgto & wphpmsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, msgclass.msgtype, msglist[msgclass.msgtype].msgto);return;}
	byteArrays ba = msgclass.encodeMsgClass();
	CreateMessage(GData::moduleindex, wphpindex, msgclass.msgtype, clientindex, ba.getlength(), ba.toVoid());
}

void CreateMessage2Simulator(int clientindex, MsgBaseClass& msgclass)
{
	if (clientindex <= 0) return;
	if (msglist.find(msgclass.msgtype) == msglist.end()) {wserPrintErr("Error msg type:%d %d!\n", clientindex, msgclass.msgtype);return;}
	if (msglist[msgclass.msgtype].msgto & wsimulatormsgindex == 0) {wserPrintErr("Error msg target:%d %d %d!\n", clientindex, msgclass.msgtype, msglist[msgclass.msgtype].msgto);return;}
	byteArrays ba = msgclass.encodeMsgClass();
	CreateMessage(GData::moduleindex, wsimulatorindex, msgclass.msgtype, clientindex, ba.getlength(), ba.toVoid());
}

int pround = 0;
pthread_mutex_t proundmutex;

int getCurrentRound()
{
	pthread_mutex_lock(&proundmutex);
	int rval = pround;
	if (pround >= servermsglength-1)
		pround = 0;
	else
		pround++;
	pthread_mutex_unlock(&proundmutex);
	return rval;
}


void wserInitMsgHandle(int mindex)
{
	wserSection sect("config/msglist/msglist.xml");
	wserSectionNode* fnode = sect.GetSubNode("")->child;
	while (fnode) {
		wserSection file(fnode->getvalue());
		wserSectionNode* node = file.GetSubNode("")->child;
		while (node) {
			msginfo mi;
			mi.id = file.GetInteger(node->getkeyname()+"|id");
			mi.name = file.GetString(node->getkeyname()+"|name");
			mi.protocol = file.GetString(node->getkeyname()+"|protocol");
			mi.luafunc = file.GetString(node->getkeyname()+"|luafunc");
			mi.comment = file.GetString(node->getkeyname()+"|comment");
			mi.nolua = file.GetInteger(node->getkeyname()+"|nolua");
			mi.msgto = file.GetInteger(node->getkeyname()+"|msgto");
			msglist.insert(pair<int, msginfo>(mi.id, mi));
			node = node->sibling;
		}
		fnode = fnode->sibling;
	}

	wserSection sect1("config/timecb/timecb.xml");
	wserSectionNode* tnode = sect1.GetSubNode("")->child;
	while (tnode) {
		int id = atoi(tnode->getkeyname().c_str());
		std::string name = sect1.GetString(tnode->getkeyname()+"|name");
		int interval = sect1.GetInteger(tnode->getkeyname()+"|interval");
		std::string comment = sect1.GetString(tnode->getkeyname()+"|comment");
		int recvproc = sect1.GetInteger(tnode->getkeyname()+"|recvproc");
		timeoutlist.insert(pair<int, TimeoutInfo>(id, TimeoutInfo(id, name, interval, comment, recvproc)));
		tnode = tnode->sibling;
	}


	int i, j, ret, msgid;key_t key;
	pthread_mutex_init(&m_msgrcvMutex, 0);
	pthread_mutex_init(&proundmutex, 0);
	for (i = 0;i < GData::modulelist.size();i++) {
		key = ftok((GData::modulelist[i].modulename+".msg").c_str(), 'a');
		if (key == -1)  break;
		wserPrintMsg("msgkey.%s\t:%#x\n", GData::modulelist[i].modulename.c_str(), (int)key);
		msgid = msgget(key, ((mindex == MODULE_WMAIN)?IPC_CREAT:0)|0666);
		if (mindex == MODULE_WMAIN) {
			msgctl(msgid, IPC_RMID, NULL);
			msgid = msgget(key, IPC_CREAT|0666);
		}
		if (msgid == -1) break;
		GData::modulelist[i].msgid = msgid;
		pthread_t pmsgqueueid;
		if (i == GData::moduleindex) {
			ret = pthread_create(&pmsgqueueid, NULL, MsgHandleCb, NULL);
		}
	}
}

void wserUninitMsgHandle()
{
	pthread_mutex_destroy(&m_msgrcvMutex);
	pthread_mutex_destroy(&proundmutex);
}

} //namespace MsgHandle

} //namespace WServer

#endif //__ENV_CPP__
